package com.ruoyi.common.utils.http;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.SSLClientCustom;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;

import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * 功能说明: 接口请求工具类<br>
 * 系统版本: v1.0<br>
 * 开发人员: @author Mr.Wen<br>
 * 开发时间: 2019-9-11<br>
 */
public class HttpPostUtil {
    private static String CONTENTTYPE = "text/html";
    private static String CHARSET = "utf-8";

    @Value("${httpset.maxConnectionsPerHost}")
    private static int  maxConnectionsPerHost;
    @Value("${httpset.maxTotalConnections}")
    private static int  maxTotalConnections;
    @Value("${httpset.soTimeOut}")
    private static int  soTimeOut;
    @Value("${httpset.connectionTimeOut}")
    private static int  connectionTimeOut;

    private static Logger logger = LogManager.getLogger(HttpPostUtil.class);

    private static MultiThreadedHttpConnectionManager connectionManager = null;

    static {
        connectionManager = new MultiThreadedHttpConnectionManager();
        connectionManager.getParams().setDefaultMaxConnectionsPerHost(maxConnectionsPerHost);
        connectionManager.getParams().setMaxTotalConnections(maxTotalConnections);
        connectionManager.getParams().setSoTimeout(soTimeOut);
        connectionManager.getParams().setConnectionTimeout(connectionTimeOut);
    }

    /**
     * xml内容post请求
     *
     * @param url
     * @param content
     * @return
     */
    public static String postXml(String url, String content) {
        Long time = System.currentTimeMillis();
        PostMethod httpMethod = null;
        String log = "".concat(content);
        String response = "";
        try {
            int index1 = log.indexOf("<password>");
            int index2 = log.indexOf("</password>");
            if (index1 > 0) {
                String a1 = log.substring(0, index1 + "<password>".length());
                String a2 = log.substring(index2, log.length());
                if (index2 > index1 + "<password>".length()) {
                    log = a1 + "*******" + a2;
                }
            }
            HttpClient httpClient = new HttpClient(connectionManager);
            httpMethod = new PostMethod(url);
            RequestEntity requestEntity = new StringRequestEntity(content, CONTENTTYPE, CHARSET);
            httpMethod.setRequestEntity(requestEntity);
            int state = httpClient.executeMethod(httpMethod);
            Long time2 = System.currentTimeMillis();
            if (state == 200) {
                response = new String(httpMethod.getResponseBody(), CHARSET);
                response = StringEscapeUtils.unescapeHtml(response);
            } else {
                if (httpMethod.getResponseBody() != null) {
                    response = new String(httpMethod.getResponseBody(), CHARSET);
                    response = StringEscapeUtils.unescapeHtml(response);
                }
            }
            String printLog = String.format("请求接口：url = [%s] , start = [%s] , end = [%s] , 耗时 = [%s] ," + "请求包 = [%s] ,应答状态 = [%s] ,应答包 = [%s]", url, time, time2, time2 - time, log, state, response);
            printLog = printLog.replaceAll("\r|\n", "");
            logger.info(printLog);
            if (state == 200) {
                return response;
            }
        } catch (Exception e) {
            long time2 = System.currentTimeMillis();
            response = "接口请求异常：" + e.getMessage();
            String printLog = String.format("请求接口：url = [%s] , start = [%s] , end = [%s]," + "请求包 = [%s] ,应答包 = [%s]", url, time, time2, log, response);
            printLog = printLog.replaceAll("\r|\n", "");
            logger.info(printLog);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * post json
     * @param url
     * @param data
     * @return
     */
    public static JSONObject postJson(String url, Map<String, Object> data) {
        return postJson(url, data, "");
    }

    public static JSONObject postJson(String url, Map<String, Object> data, String access_token) {
        PostMethod httpMethod = null;
        String response = null;
        try {
            HttpClient httpClient = new HttpClient(connectionManager);
            httpMethod = new PostMethod(url);
            RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(data),
                    "application/json", CHARSET);
            if (StringUtils.isNotBlank(access_token)) {
                httpMethod.setRequestHeader("Access-Token", access_token);
            }
            httpMethod.setRequestEntity(requestEntity);
            int state = httpClient.executeMethod(httpMethod);
            if (state == 200) {
                if (httpMethod.getResponseBody() != null) {
                    response = new String(httpMethod.getResponseBody(), CHARSET);
                    return JSONObject.parseObject(response);
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * post json请求带自定义头，支持https
     * @param url
     * @param data
     * @param headers
     * @return
     */
    public static JSONObject postJson(String url, Map<String, Object> data, Map<String, String> headers) {
        JSONObject jsonResult = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = null;
        try {
            httpClient = createHttpClient(url);
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(60000).setConnectTimeout(60000).build();
            httpPost.setConfig(requestConfig);
            if (headers != null && headers.size() > 0) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    httpPost.setHeader(entry.getKey(), entry.getValue());
                }
            }
            String req = "";
            if (null != data) {
                req = JSONObject.toJSONString(data);
                StringEntity entity = new StringEntity(req, "utf-8");
                entity.setContentEncoding("UTF-8");
                entity.setContentType("application/json");
                httpPost.setEntity(entity);
            }
            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(response.getEntity(), "utf-8");
                jsonResult = JSONObject.parseObject(result);
                logger.info("请求:" + url + "[" + req + "], 返回结果:" + jsonResult);
            } else {
                logger.info("请求:" + url + "[" + req + "], 返回失败:" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("post请求提交异常:" + url, e);
        } finally {
            closeHttpClient(response, httpClient);
        }
        return jsonResult;
    }

    public static JSONObject get(String url) {
        return execute(url, HttpGet.METHOD_NAME, null, null, null);
    }

    public static JSONObject execute(String url, String methodName, Map<String, Object> data, Map<String, String> headers) {
        return execute(url, methodName, data, null, headers);
    }

    /**
     * http请求支持自定义header和自定义方法
     * @param url
     * @param methodName post/get/put/delete等
     * @param data
     * @param byte_data body文件流
     * @param headers
     * @return
     */
    public static JSONObject execute(String url, String methodName, Map<String, Object> data, byte[] byte_data, Map<String, String> headers) {
        JSONObject jsonResult = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = null;
        try {
            httpClient = createHttpClient(url);
            HttpRequestBase request = getRquest(methodName);
            request.setURI(URI.create(url));
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(60000).setConnectTimeout(60000).build();
            request.setConfig(requestConfig);
            if (headers != null && headers.size() > 0) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    request.setHeader(entry.getKey(), entry.getValue());
                }
            }
            if (null != data) {
                HttpEntity entity = EntityBuilder.create()
                        .setContentEncoding("utf-8")
                        .setContentType(ContentType.APPLICATION_JSON)
                        .setText(JSONObject.toJSONString(data))
                        .build();
                ((HttpEntityEnclosingRequestBase) request).setEntity(entity);
            }
            if (byte_data != null) {
                ((HttpEntityEnclosingRequestBase) request).setEntity(new ByteArrayEntity(byte_data));
            }
            logger.info("请求:[{}]，参数：[{}]", url, data);
            response = httpClient.execute(request);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(response.getEntity(), "utf-8");
                jsonResult = JSONObject.parseObject(result);
                logger.info("请求:[{}]，返回结果:[{}]", url, jsonResult);
            } else {
                logger.info("请求:[{}]，返回结果:[{}]", url, response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("请求提交异常:" + url, e);
        } finally {
            closeHttpClient(response, httpClient);
        }
        return jsonResult;
    }

    private static HttpRequestBase getRquest(String method) {
        if (HttpGet.METHOD_NAME.equals(method)) {
            return new HttpGet();
        } else if (HttpPost.METHOD_NAME.equals(method)) {
            return new HttpPost();
        } else if (HttpHead.METHOD_NAME.equals(method)) {
            return new HttpHead();
        } else if (HttpOptions.METHOD_NAME.equals(method)) {
            return new HttpOptions();
        } else if (HttpPut.METHOD_NAME.equals(method)) {
            return new HttpPut();
        } else if (HttpPatch.METHOD_NAME.equals(method)) {
            return new HttpPatch();
        } else if (HttpDelete.METHOD_NAME.equals(method)) {
            return new HttpDelete();
        } else if (HttpTrace.METHOD_NAME.equals(method)) {
            return new HttpTrace();
        }
        return new HttpPost();
    }

    public static void closeHttpClient(CloseableHttpResponse response, CloseableHttpClient httpClient) {
        try {
            if (response != null) {
                response.close();
            }
            if (httpClient != null) {
                httpClient.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * post https请求
     *
     * @param url
     * @param data
     * @return
     */
    public static JSONObject postJsonForHttps(String url, Map<String, Object> data) {
        JSONObject jsonResult = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = null;
        try {
            httpClient = SSLClientCustom.getHttpClinet();
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(60000).setConnectTimeout(60000).build();
            httpPost.setConfig(requestConfig);
            if (null != data) {
                StringEntity entity = new StringEntity(JSONObject.toJSONString(data), "utf-8");
                entity.setContentEncoding("UTF-8");
                entity.setContentType("application/json");
                httpPost.setEntity(entity);
            }
            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(response.getEntity(), "utf-8");
                jsonResult = JSONObject.parseObject(result);
            } else {
                logger.info("post请求提交失败:" + url + ":" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("post请求提交失败:" + url, e);
        } finally {
            // 关闭连接,释放资源
            try {
                response.close();
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return jsonResult;
    }

    private static CloseableHttpClient createHttpClient(String url) {
        if (url != null && url.indexOf("https") > -1) {
            try {
                SSLContext sslContext = (new SSLContextBuilder()).loadTrustMaterial((KeyStore) null, new TrustStrategy() {
                    public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                        return true;
                    }
                }).build();
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
                return HttpClients.custom().setSSLSocketFactory(sslsf).build();
            } catch (Exception var3) {
                return null;
            }
        }

        return HttpClients.createDefault();
    }

    /**
     * POST请求form-data格式数据
     *
     * @param url
     * @param data
     * @return
     */
    public static JSONObject postFormData(String url, Map<String, String> data) {
        String result = null;
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            RequestConfig requestConfig = RequestConfig.custom()
                    .setSocketTimeout(60000)
                    .setConnectTimeout(60000)
                    .setConnectionRequestTimeout(60000).build();
            client = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
            URIBuilder uriBuilder = new URIBuilder(url);

            HttpPost httpPost = new HttpPost(uriBuilder.build());
            httpPost.setHeader("Connection", "Keep-Alive");
            httpPost.setHeader("Charset", CHARSET);
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            Iterator<Map.Entry<String, String>> it = data.entrySet().iterator();
            List<NameValuePair> params = new ArrayList<>();
            while (it.hasNext()) {
                Map.Entry<String, String> entry = it.next();
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue());
                params.add(pair);
            }

            httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

            response = client.execute(httpPost);
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, CHARSET);
                }
            }
        } catch (ClientProtocolException e) {
            logger.error("post form-data创建连接失败", e.getMessage());
        } catch (IOException e) {
            logger.error("post form-data请求/响应失败", e.getMessage());
        } catch (URISyntaxException e) {
            logger.error("post form-data请求/响应失败", e.getMessage());
        }

        return StringUtils.isBlank(result) ? null : JSONObject.parseObject(result);
    }


    /**
     * 按照“参数=参数值”的模式用“&”字符拼接成字符串
     *
     * @param params
     * @return
     */
    public static String getRequestParams(Map<String, Object> params) {
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        StringBuilder paramstr = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = MapUtils.getString(params, key, "");
            if (i == keys.size() - 1) {
                paramstr.append(key).append("=").append(value);
            } else {
                paramstr.append(key).append("=").append(value).append("&");
            }
        }
        return paramstr.toString();
    }

    public static void main(String[] args) {
        // 组装请求
        StringBuffer sb = new StringBuffer();
        sb.append("user_id=2233&user_pwd=onway");
    }

    public static String postForm(String url, Map<String, String> params)
            throws Exception {
        String result = "";
        BufferedReader in = null;
        String content = getParamStr(params);
        try {
            System.out.println("POST请求的URL为：" + url);
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new TrustAnyTrustManager()},
                    new java.security.SecureRandom());
            URL console = new URL(url);
            HttpsURLConnection connection = (HttpsURLConnection)
                    console.openConnection();
            connection.setSSLSocketFactory(sc.getSocketFactory());
            connection.setHostnameVerifier(new TrustAnyHostnameVerifier());
            connection.setDoOutput(true);
            connection.connect();
            DataOutputStream out = new
                    DataOutputStream(connection.getOutputStream());
            out.write(content.getBytes("UTF-8"));
            // 刷新、关闭
            out.flush();
            out.close();
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new
                    InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
            System.out.println("获取的结果为：" + result);
        } catch (Exception e) {
            System.out.println("发送POST请求出现异常！" + e);
            e.printStackTrace();
            throw e;
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                //e2.printStackTrace();
                throw e2;
            }
        }
        return result;
    }

    private static String getParamStr(Map<String, String> params) {
        String paramStr = "";
        if (params != null && params.size() > 0) {
            // 获取参数列表组成参数字符串
            for (String key : params.keySet()) {
                paramStr += key + "=" + params.get(key) + "&";
            }
            //去除最后一个"&"
            paramStr = paramStr.substring(0, paramStr.length() - 1);
        }
        return paramStr;
    }

    private static class TrustAnyTrustManager implements X509TrustManager {

        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}
